home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / HENSA / MATHS / PLPLOT / PLPLOT.ZIP / src / plbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-30  |  35.9 KB  |  1,406 lines

  1. /* $Id: plbox.c,v 1.14 1994/08/29 22:05:19 mjl Exp $
  2.  * $Log: plbox.c,v $
  3.  * Revision 1.14  1994/08/29  22:05:19  mjl
  4.  * Fixed a bug that was preventing the exponential label from showing up
  5.  * under certain circumstances.
  6.  *
  7.  * Revision 1.13  1994/06/30  18:22:00  mjl
  8.  * All core source files: made another pass to eliminate warnings when using
  9.  * gcc -Wall.  Lots of cleaning up: got rid of includes of math.h or string.h
  10.  * (now included by plplot.h), and other minor changes.  Now each file has
  11.  * global access to the plstream pointer via extern; many accessor functions
  12.  * eliminated as a result.
  13.  *
  14.  * Revision 1.12  1994/04/30  16:15:04  mjl
  15.  * Fixed format field (%ld instead of %d) or introduced casts where
  16.  * appropriate to eliminate warnings given by gcc -Wall.
  17.  *
  18.  * Revision 1.11  1994/04/08  12:29:28  mjl
  19.  * Hack to prevent labels like "-0.0" on some systems, caused by roundoff.
  20.  *
  21.  * Revision 1.10  1994/03/23  07:54:08  mjl
  22.  * Replaced call to plexit() on simple (recoverable) errors with simply
  23.  * printing the error message (via plabort()) and returning.  Should help
  24.  * avoid loss of computer time in some critical circumstances (during a long
  25.  * batch run, for example).
  26. */
  27.  
  28. /*    plbox.c
  29.  
  30.     Routines for drawing axes & box around the current viewport.
  31. */
  32.  
  33. #include "plplotP.h"
  34.  
  35. static PLFLT xlog[8] =
  36. {
  37.     0.301030, 0.477121, 0.602060, 0.698970,
  38.     0.778151, 0.845098, 0.903090, 0.954243
  39. };
  40.  
  41. /* Static function prototypes */
  42.  
  43. static void
  44. plxybx(const char *opt, const char *label, PLFLT wx1, PLFLT wy1,
  45.        PLFLT wx2, PLFLT wy2, PLFLT vmin, PLFLT vmax,
  46.        PLFLT tick, PLINT nsub, PLINT nolast, PLINT *digits);
  47.  
  48. static void
  49. plzbx(const char *opt, const char *label, PLINT right, PLFLT dx, PLFLT dy,
  50.       PLFLT wx, PLFLT wy1, PLFLT wy2, PLFLT vmin, PLFLT vmax,
  51.       PLFLT tick, PLINT nsub, PLINT *digits);
  52.  
  53. static void
  54. plxytx(PLFLT wx1, PLFLT wy1, PLFLT wx2, PLFLT wy2,
  55.        PLFLT disp, PLFLT pos, PLFLT just, const char *text);
  56.  
  57. static void
  58. plztx(const char *opt, PLFLT dx, PLFLT dy, PLFLT wx, PLFLT wy1,
  59.       PLFLT wy2, PLFLT disp, PLFLT pos, PLFLT just, const char *text);
  60.  
  61. static void
  62. plform(PLFLT value, PLINT scale, PLINT prec, char *result);
  63.  
  64. /*----------------------------------------------------------------------*\
  65.  * void plbox()
  66.  *
  67.  * This draws a box around the current viewport. XOPT and YOPT are
  68.  * character strings which define the box as follows:
  69.  *
  70.  * A: Draw axis (X is horizontal line Y=0, Y is vertical line X=0)
  71.  * B: Draw bottom (X) or left (Y) edge of frame
  72.  * C: Draw top (X) or right (Y) edge of frame
  73.  * G: Draws a grid at the major tick interval
  74.  * I: Inverts tick marks
  75.  * L: Logarithmic axes, major ticks at decades, minor ticks at units
  76.  * N: Write numeric label at conventional location
  77.  * M: Write numeric label at unconventional location
  78.  * T: Draw major tick marks
  79.  * S: Draw minor tick marks
  80.  * V: (for Y only) Label vertically
  81.  *
  82.  * xtick, ytick are the major tick intervals required, zero for
  83.  * automatic selection
  84.  *
  85.  * nxsub, nysub are the number of subtick intervals in a major tick
  86.  * interval
  87. \*----------------------------------------------------------------------*/
  88.  
  89. void
  90. c_plbox(const char *xopt, PLFLT xtick, PLINT nxsub,
  91.     const char *yopt, PLFLT ytick, PLINT nysub)
  92. {
  93.     static char string[40];
  94.     PLINT lax, lbx, lcx, lgx, lix, llx, lmx, lnx, lsx, ltx;
  95.     PLINT lay, lby, lcy, lgy, liy, lly, lmy, lny, lsy, lty, lvy;
  96.     PLINT xmajor, xminor, ymajor, yminor;
  97.     PLINT xmode, xprec, xdigmax, xdigits, xscale;
  98.     PLINT ymode, yprec, ydigmax, ydigits, yscale;
  99.     PLINT i, i1x, i2x, i3x, i4x, i1y, i2y, i3y, i4y, it0;
  100.     PLINT nxsub1, nysub1;
  101.     PLINT lxmin, lxmax, lymin, lymax;
  102.     PLINT pxmin, pxmax, pymin, pymax;
  103.     PLINT vppxmi, vppxma, vppymi, vppyma;
  104.     PLINT lstring;
  105.     PLFLT xtick1, ytick1, vpwxmi, vpwxma, vpwymi, vpwyma;
  106.     PLFLT pos, tn, tp, temp, offset, height, xcrit, ycrit;
  107.  
  108.     if (plsc->level < 3) {
  109.     plabort("plbox: Please set up window first");
  110.     return;
  111.     }
  112.  
  113.     /* Open  the clip limits to the subpage limits */
  114.  
  115.     plP_gclp(&lxmin, &lxmax, &lymin, &lymax);
  116.     plP_gphy(&pxmin, &pxmax, &pymin, &pymax);
  117.     plP_sclp(pxmin, pxmax, pymin, pymax);
  118.  
  119.     plP_gvpp(&vppxmi, &vppxma, &vppymi, &vppyma);
  120.  
  121.     /* Tick and subtick sizes in device coords */
  122.  
  123.     xmajor = MAX(ROUND(plsc->majht * plsc->ypmm), 1);
  124.     ymajor = MAX(ROUND(plsc->majht * plsc->xpmm), 1);
  125.     xminor = MAX(ROUND(plsc->minht * plsc->ypmm), 1);
  126.     yminor = MAX(ROUND(plsc->minht * plsc->xpmm), 1);
  127.  
  128.     xtick1 = xtick;
  129.     nxsub1 = nxsub;
  130.     ytick1 = ytick;
  131.     nysub1 = nysub;
  132.  
  133.     lax = plP_stsearch(xopt, 'a');
  134.     lbx = plP_stsearch(xopt, 'b');
  135.     lcx = plP_stsearch(xopt, 'c');
  136.     lgx = plP_stsearch(xopt, 'g');
  137.     lix = plP_stsearch(xopt, 'i');
  138.     llx = plP_stsearch(xopt, 'l');
  139.     lmx = plP_stsearch(xopt, 'm');
  140.     lnx = plP_stsearch(xopt, 'n');
  141.     lsx = plP_stsearch(xopt, 's');
  142.     ltx = plP_stsearch(xopt, 't');
  143.  
  144.     lay = plP_stsearch(yopt, 'a');
  145.     lby = plP_stsearch(yopt, 'b');
  146.     lcy = plP_stsearch(yopt, 'c');
  147.     lgy = plP_stsearch(yopt, 'g');
  148.     liy = plP_stsearch(yopt, 'i');
  149.     lly = plP_stsearch(yopt, 'l');
  150.     lmy = plP_stsearch(yopt, 'm');
  151.     lny = plP_stsearch(yopt, 'n');
  152.     lsy = plP_stsearch(yopt, 's');
  153.     lty = plP_stsearch(yopt, 't');
  154.     lvy = plP_stsearch(yopt, 'v');
  155.  
  156.     plP_gvpw(&vpwxmi, &vpwxma, &vpwymi, &vpwyma);
  157.  
  158.     lax = lax && (vpwymi * vpwyma < 0.0) && !llx;
  159.     lay = lay && (vpwxmi * vpwxma < 0.0) && !lly;
  160.  
  161.     plgxax(&xdigmax, &xdigits);
  162.     plgyax(&ydigmax, &ydigits);
  163.  
  164.     if (llx)
  165.     xtick1 = 1.0;
  166.     if (lly)
  167.     ytick1 = 1.0;
  168.  
  169.     /* Calculate tick spacing */
  170.  
  171.     if (ltx || lgx)
  172.     pldtik(vpwxmi, vpwxma, &xtick1, &nxsub1, &xmode, &xprec, xdigmax,
  173.            &xscale);
  174.  
  175.     if (lty || lgy)
  176.     pldtik(vpwymi, vpwyma, &ytick1, &nysub1, &ymode, &yprec, ydigmax,
  177.            &yscale);
  178.  
  179.     /* Set up tick variables */
  180.  
  181.     if (lix) {
  182.     i1x = xminor;
  183.     i2x = 0;
  184.     i3x = xmajor;
  185.     i4x = 0;
  186.     }
  187.     else {
  188.     i1x = 0;
  189.     i2x = xminor;
  190.     i3x = 0;
  191.     i4x = xmajor;
  192.     }
  193.  
  194.     if (liy) {
  195.     i1y = yminor;
  196.     i2y = 0;
  197.     i3y = ymajor;
  198.     i4y = 0;
  199.     }
  200.     else {
  201.     i1y = 0;
  202.     i2y = yminor;
  203.     i3y = 0;
  204.     i4y = ymajor;
  205.     }
  206.  
  207.     /* Draw the bottom edge of the box */
  208.  
  209.     if (lbx) {
  210.     plP_movphy(vppxmi, vppymi);
  211.     if (ltx) {
  212.         tp = xtick1 * floor(vpwxmi / xtick1);
  213.         for (;;) {
  214.         tn = tp + xtick1;
  215.         if (lsx) {
  216.             if (llx) {
  217.             for (i = 0; i <= 7; i++) {
  218.                 temp = tp + xlog[i];
  219.                 if (BETW(temp, vpwxmi, vpwxma))
  220.                 plxtik(plP_wcpcx(temp), vppymi, i1x, i2x);
  221.             }
  222.             }
  223.             else {
  224.             for (i = 1; i <= nxsub1 - 1; i++) {
  225.                 temp = tp + i * (tn - tp) / nxsub1;
  226.                 if (BETW(temp, vpwxmi, vpwxma))
  227.                 plxtik(plP_wcpcx(temp), vppymi, i1x, i2x);
  228.             }
  229.             }
  230.         }
  231.         if (!BETW(tn, vpwxmi, vpwxma))
  232.             break;
  233.         plxtik(plP_wcpcx(tn), vppymi, i3x, i4x);
  234.         tp = tn;
  235.         }
  236.     }
  237.     plP_draphy(vppxma, vppymi);
  238.     }
  239.  
  240.     /* Draw right-hand edge of box */
  241.  
  242.     if (lcy) {
  243.     plP_movphy(vppxma, vppymi);
  244.     if (lty) {
  245.         tp = ytick1 * floor(vpwymi / ytick1);
  246.         for (;;) {
  247.         tn = tp + ytick1;
  248.         if (lsy) {
  249.             if (lly) {
  250.             for (i = 0; i <= 7; i++) {
  251.                 temp = tp + xlog[i];
  252.                 if (BETW(temp, vpwymi, vpwyma))
  253.                 plytik(vppxma, plP_wcpcy(temp), i2y, i1y);
  254.             }
  255.             }
  256.             else {
  257.             for (i = 1; i <= nysub1 - 1; i++) {
  258.                 temp = tp + i * (tn - tp) / nysub1;
  259.                 if (BETW(temp, vpwymi, vpwyma))
  260.                 plytik(vppxma, plP_wcpcy(temp), i2y, i1y);
  261.             }
  262.             }
  263.         }
  264.         if (!BETW(tn, vpwymi, vpwyma))
  265.             break;
  266.         plytik(vppxma, plP_wcpcy(tn), i4y, i3y);
  267.         tp = tn;
  268.         }
  269.     }
  270.     plP_draphy(vppxma, vppyma);
  271.     }
  272.  
  273.     /* Draw the top edge of the box */
  274.  
  275.     if (lcx) {
  276.     plP_movphy(vppxma, vppyma);
  277.     if (ltx) {
  278.         tp = xtick1 * (floor(vpwxma / xtick1) + 1);
  279.         for (;;) {
  280.         tn = tp - xtick1;
  281.         if (lsx) {
  282.             if (llx) {
  283.             for (i = 7; i >= 0; i--) {
  284.                 temp = tn + xlog[i];
  285.                 if (BETW(temp, vpwxmi, vpwxma))
  286.                 plxtik(plP_wcpcx(temp), vppyma, i2x, i1x);
  287.             }
  288.             }
  289.             else {
  290.             for (i = nxsub1 - 1; i >= 1; i--) {
  291.                 temp = tn + i * (tp - tn) / nxsub1;
  292.                 if (BETW(temp, vpwxmi, vpwxma))
  293.                 plxtik(plP_wcpcx(temp), vppyma, i2x, i1x);
  294.             }
  295.             }
  296.         }
  297.         if (!BETW(tn, vpwxmi, vpwxma))
  298.             break;
  299.         plxtik(plP_wcpcx(tn), vppyma, i4x, i3x);
  300.         tp = tn;
  301.         }
  302.     }
  303.     plP_draphy(vppxmi, vppyma);
  304.     }
  305.  
  306.     /* Draw left-hand edge of box */
  307.  
  308.     if (lby) {
  309.     plP_movphy(vppxmi, vppyma);
  310.     if (lty) {
  311.         tp = ytick1 * (floor(vpwyma / ytick1) + 1);
  312.         for (;;) {
  313.         tn = tp - ytick1;
  314.         if (lsy) {
  315.             if (lly) {
  316.             for (i = 7; i >= 0; i--) {
  317.                 temp = tn + xlog[i];
  318.                 if (BETW(temp, vpwymi, vpwyma))
  319.                 plytik(vppxmi, plP_wcpcy(temp), i1y, i2y);
  320.             }
  321.             }
  322.             else {
  323.             for (i = nysub1 - 1; i >= 1; i--) {
  324.                 temp = tn + i * (tp - tn) / nysub1;
  325.                 if (BETW(temp, vpwymi, vpwyma))
  326.                 plytik(vppxmi, plP_wcpcy(temp), i1y, i2y);
  327.             }
  328.             }
  329.         }
  330.         if (!BETW(tn, vpwymi, vpwyma))
  331.             break;
  332.         plytik(vppxmi, plP_wcpcy(tn), i3y, i4y);
  333.         tp = tn;
  334.         }
  335.     }
  336.     plP_draphy(vppxmi, vppymi);
  337.     }
  338.  
  339.     /* Draw the horizontal axis */
  340.  
  341.     if (lax) {
  342.     it0 = plP_wcpcy(0.0);
  343.     plP_movphy(vppxmi, it0);
  344.     if (ltx) {
  345.         tp = xtick1 * floor(vpwxmi / xtick1);
  346.         for (;;) {
  347.         tn = tp + xtick1;
  348.         if (lsx) {
  349.             if (llx) {
  350.             for (i = 0; i <= 7; i++) {
  351.                 temp = tp + xlog[i];
  352.                 if (BETW(temp, vpwxmi, vpwxma))
  353.                 plxtik(plP_wcpcx(temp), it0, xminor, xminor);
  354.             }
  355.             }
  356.             else {
  357.             for (i = 1; i <= nxsub1 - 1; i++) {
  358.                 temp = tp + i * (tn - tp) / nxsub1;
  359.                 if (BETW(temp, vpwxmi, vpwxma))
  360.                 plxtik(plP_wcpcx(temp), it0, xminor, xminor);
  361.             }
  362.             }
  363.         }
  364.         if (!BETW(tn, vpwxmi, vpwxma))
  365.             break;
  366.         plxtik(plP_wcpcx(tn), it0, xmajor, xmajor);
  367.         tp = tn;
  368.         }
  369.     }
  370.     plP_draphy(vppxma, it0);
  371.     }
  372.  
  373.     /* Draw the vertical axis */
  374.  
  375.     if (lay) {
  376.     it0 = plP_wcpcx(0.0);
  377.     plP_movphy(it0, vppymi);
  378.     if (lty) {
  379.         tp = ytick1 * floor(vpwymi / ytick1);
  380.         for (;;) {
  381.         tn = tp + ytick1;
  382.         if (lsy) {
  383.             if (lly) {
  384.             for (i = 0; i <= 7; i++) {
  385.                 temp = tp + xlog[i];
  386.                 if (BETW(temp, vpwymi, vpwyma))
  387.                 plytik(it0, plP_wcpcy(temp), yminor, yminor);
  388.             }
  389.             }
  390.             else {
  391.             for (i = 1; i <= nysub1 - 1; i++) {
  392.                 temp = tp + i * (tn - tp) / nysub1;
  393.                 if (BETW(temp, vpwymi, vpwyma))
  394.                 plytik(it0, plP_wcpcy(temp), yminor, yminor);
  395.             }
  396.             }
  397.         }
  398.         if (!BETW(tn, vpwymi, vpwyma))
  399.             break;
  400.         plytik(it0, plP_wcpcy(tn), ymajor, ymajor);
  401.         tp = tn;
  402.         }
  403.     }
  404.     plP_draphy(it0, vppyma);
  405.     }
  406.  
  407.     /* Draw grid in x direction */
  408.     /* xcrit is the minimim distance away (in fractional number of ticks) */
  409.     /* from the boundary a grid line can be drawn.  If you are too close, */
  410.     /* it looks bad.  The previous setting was 0.5 which was too far. */
  411.  
  412.     if (lgx) {
  413.     xcrit = 0.1;
  414.     tp = xtick1 * (1. + floor(vpwxmi / xtick1 + xcrit));
  415.     for (tn = tp; BETW(tn + xtick1*xcrit, vpwxmi, vpwxma); tn += xtick1)
  416.         pljoin(tn, vpwymi, tn, vpwyma);
  417.     }
  418.  
  419.     /* Draw grid in y direction */
  420.     /* ycrit behaves analogously to xcrit */
  421.  
  422.     if (lgy) {
  423.     ycrit = 0.1;
  424.     tp = ytick1 * (1. + floor(vpwymi / ytick1 + 0.05));
  425.     for (tn = tp; BETW(tn + ytick1*ycrit, vpwymi, vpwyma); tn += ytick1)
  426.         pljoin(vpwxmi, tn, vpwxma, tn);
  427.     }
  428.  
  429.     /* Write horizontal label(s) */
  430.  
  431.     if ((lmx || lnx) && ltx) {
  432.     tp = xtick1 * (1. + floor(vpwxmi / xtick1));
  433.     for (tn = tp; BETW(tn, vpwxmi, vpwxma); tn += xtick1) {
  434.         if (!llx)
  435.         plform(tn, xscale, xprec, string);
  436.         else
  437.         sprintf(string, "10#u%d", (int) ROUND(tn));
  438.  
  439.         pos = (tn - vpwxmi) / (vpwxma - vpwxmi);
  440.         if (lnx)
  441.         plmtex("b", 1.5, pos, 0.5, string);
  442.         if (lmx)
  443.         plmtex("t", 1.5, pos, 0.5, string);
  444.     }
  445.     xdigits = 2;
  446.     plsxax(xdigmax, xdigits);
  447.  
  448. /* Write separate exponential label if mode = 1. */
  449.  
  450.     if (!llx && xmode) {
  451.         pos = 1.0;
  452.         height = 3.2;
  453.         sprintf(string, "(x10#u%d#d)", (int) xscale);
  454.         if (lnx)
  455.         plmtex("b", height, pos, 0.5, string);
  456.         if (lmx)
  457.         plmtex("t", height, pos, 0.5, string);
  458.     }
  459.     }
  460.  
  461.     /* Write vertical label(s) */
  462.  
  463.     if ((lmy || lny) && lty) {
  464.     ydigits = 0;
  465.     tp = ytick1 * (1. + floor(vpwymi / ytick1));
  466.     for (tn = tp; BETW(tn, vpwymi, vpwyma); tn += ytick1) {
  467.         if (!lly)
  468.         plform(tn, yscale, yprec, string);
  469.         else
  470.         sprintf(string, "10#u%d", (int) ROUND(tn));
  471.  
  472.         pos = (tn - vpwymi) / (vpwyma - vpwymi);
  473.         if (lny) {
  474.         if (lvy)
  475.             plmtex("lv", 0.5, pos, 1.0, string);
  476.         else
  477.             plmtex("l", 1.5, pos, 0.5, string);
  478.         }
  479.         if (lmy) {
  480.         if (lvy)
  481.             plmtex("rv", 0.5, pos, 0.0, string);
  482.         else
  483.             plmtex("r", 1.5, pos, 0.5, string);
  484.         }
  485.         lstring = strlen(string);
  486.         ydigits = MAX(ydigits, lstring);
  487.     }
  488.     if (!lvy)
  489.         ydigits = 2;
  490.  
  491.     plsyax(ydigmax, ydigits);
  492.  
  493. /* Write separate exponential label if mode = 1. */
  494.  
  495.     if (!lly && ymode) {
  496.         sprintf(string, "(x10#u%d#d)", (int) yscale);
  497.         offset = 0.02;
  498.         height = 2.0;
  499.         if (lny) {
  500.         pos = 0.0 - offset;
  501.         plmtex("t", height, pos, 1.0, string);
  502.         }
  503.         if (lmy) {
  504.         pos = 1.0 + offset;
  505.         plmtex("t", height, pos, 0.0, string);
  506.         }
  507.     }
  508.     }
  509.     /* Restore the clip limits to viewport edge */
  510.  
  511.     plP_sclp(lxmin, lxmax, lymin, lymax);
  512. }
  513.  
  514. /*----------------------------------------------------------------------*\
  515.  * void plaxes()
  516.  *
  517.  * This functions similarly to plbox() except that the origin of the axes
  518.  * is placed at the user-specified point (x0, y0).
  519. \*----------------------------------------------------------------------*/
  520.  
  521. void
  522. c_plaxes(PLFLT x0, PLFLT y0, const char *xopt, PLFLT xtick, PLINT nxsub,
  523.      const char *yopt, PLFLT ytick, PLINT nysub)
  524. {
  525.     static char string[40];
  526.     PLINT lbx, lcx, lgx, llx, lmx, lnx, lsx, ltx;
  527.     PLINT lby, lcy, lgy, lly, lmy, lny, lsy, lty, lvy;
  528.     PLINT xmajor, xminor, ymajor, yminor;
  529.     PLINT xorigin, yorigin;
  530.     PLINT xmode, xprec, xdigmax, xdigits, xscale;
  531.     PLINT ymode, yprec, ydigmax, ydigits, yscale;
  532.     PLINT i, i1x, i2x, i3x, i4x, i1y, i2y, i3y, i4y;
  533.     PLINT nxsub1, nysub1;
  534.     PLINT lxmin, lxmax, lymin, lymax;
  535.     PLINT pxmin, pxmax, pymin, pymax;
  536.     PLINT vppxmi, vppxma, vppymi, vppyma;
  537.     PLINT lstring;
  538.     PLFLT xtick1, ytick1, vpwxmi, vpwxma, vpwymi, vpwyma;
  539.     PLFLT pos, tn, tp, temp, offset, height;
  540.  
  541.     if (plsc->level < 3) {
  542.     plabort("plaxes: Please set up window first");
  543.     return;
  544.     }
  545.  
  546.     /* Open  the clip limits to the subpage limits */
  547.  
  548.     plP_gclp(&lxmin, &lxmax, &lymin, &lymax);
  549.     plP_gphy(&pxmin, &pxmax, &pymin, &pymax);
  550.     plP_sclp(pxmin, pxmax, pymin, pymax);
  551.  
  552.     plP_gvpp(&vppxmi, &vppxma, &vppymi, &vppyma);
  553.  
  554.     /* convert world coordinates to physical     */
  555.  
  556.     xorigin = plP_wcpcx(x0);
  557.     yorigin = plP_wcpcy(y0);
  558.  
  559.     /* Tick and subtick sizes in device coords */
  560.  
  561.     xmajor = MAX(ROUND(plsc->majht * plsc->ypmm), 1);
  562.     ymajor = MAX(ROUND(plsc->majht * plsc->xpmm), 1);
  563.     xminor = MAX(ROUND(plsc->minht * plsc->ypmm), 1);
  564.     yminor = MAX(ROUND(plsc->minht * plsc->xpmm), 1);
  565.  
  566.     xtick1 = xtick;
  567.     nxsub1 = nxsub;
  568.     ytick1 = ytick;
  569.     nysub1 = nysub;
  570.  
  571.     lbx = plP_stsearch(xopt, 'b');
  572.     lcx = plP_stsearch(xopt, 'c');
  573.     lgx = plP_stsearch(xopt, 'g');
  574.     llx = plP_stsearch(xopt, 'l');
  575.     lmx = plP_stsearch(xopt, 'm');
  576.     lnx = plP_stsearch(xopt, 'n');
  577.     lsx = plP_stsearch(xopt, 's');
  578.     ltx = plP_stsearch(xopt, 't');
  579.  
  580.     lby = plP_stsearch(yopt, 'b');
  581.     lcy = plP_stsearch(yopt, 'c');
  582.     lgy = plP_stsearch(yopt, 'g');
  583.     lly = plP_stsearch(yopt, 'l');
  584.     lmy = plP_stsearch(yopt, 'm');
  585.     lny = plP_stsearch(yopt, 'n');
  586.     lsy = plP_stsearch(yopt, 's');
  587.     lty = plP_stsearch(yopt, 't');
  588.     lvy = plP_stsearch(yopt, 'v');
  589.  
  590.     plP_gvpw(&vpwxmi, &vpwxma, &vpwymi, &vpwyma);
  591.  
  592.     plgxax(&xdigmax, &xdigits);
  593.     plgyax(&ydigmax, &ydigits);
  594.  
  595.     if (llx)
  596.     xtick1 = 1.0;
  597.  
  598.     if (lly)
  599.     ytick1 = 1.0;
  600.  
  601.     if (ltx || lgx)
  602.     pldtik(vpwxmi, vpwxma, &xtick1, &nxsub1, &xmode, &xprec, xdigmax,
  603.            &xscale);
  604.  
  605.     if (lty || lgy)
  606.     pldtik(vpwymi, vpwyma, &ytick1, &nysub1, &ymode, &yprec, ydigmax,
  607.            &yscale);
  608.  
  609.     /* Set up tick variables */
  610.  
  611.     i1x = xminor;
  612.     i2x = xminor;
  613.     i3x = xmajor;
  614.     i4x = xmajor;
  615.  
  616.     i1y = yminor;
  617.     i2y = yminor;
  618.     i3y = ymajor;
  619.     i4y = ymajor;
  620.  
  621.     /* draw boxing */
  622.  
  623.     if (lbx) {
  624.     plP_movphy(vppxmi, vppymi);
  625.     plP_draphy(vppxma, vppymi);
  626.     }
  627.     if (lcx) {
  628.     plP_movphy(vppxmi, vppyma);
  629.     plP_draphy(vppxma, vppyma);
  630.     }
  631.     if (lby) {
  632.     plP_movphy(vppxmi, vppymi);
  633.     plP_draphy(vppxmi, vppyma);
  634.     }
  635.     if (lcy) {
  636.     plP_movphy(vppxma, vppymi);
  637.     plP_draphy(vppxma, vppyma);
  638.     }
  639.  
  640.     /* Draw the horizontal axis */
  641.  
  642.     plP_movphy(vppxmi, yorigin);
  643.     if (ltx) {
  644.     tp = xtick1 * floor(vpwxmi / xtick1);
  645.     for (;;) {
  646.         tn = tp + xtick1;
  647.         if (lsx) {
  648.         if (llx) {
  649.             for (i = 0; i <= 7; i++) {
  650.             temp = tp + xlog[i];
  651.             if (BETW(temp, vpwxmi, vpwxma))
  652.                 plxtik(plP_wcpcx(temp), yorigin, i1x, i2x);
  653.             }
  654.         }
  655.         else {
  656.             for (i = 1; i <= nxsub1 - 1; i++) {
  657.             temp = tp + i * (tn - tp) / nxsub1;
  658.             if (BETW(temp, vpwxmi, vpwxma))
  659.                 plxtik(plP_wcpcx(temp), yorigin, i1x, i2x);
  660.             }
  661.         }
  662.         }
  663.         if (!BETW(tn, vpwxmi, vpwxma))
  664.         break;
  665.         plxtik(plP_wcpcx(tn), yorigin, i3x, i4x);
  666.         tp = tn;
  667.     }
  668.     }
  669.     plP_draphy(vppxma, yorigin);
  670.  
  671.     /* Draw vertical axis */
  672.  
  673.     if (lby) {
  674.     plP_movphy(xorigin, vppyma);
  675.     if (lty) {
  676.         tp = ytick1 * (floor(vpwyma / ytick1) + 1);
  677.         for (;;) {
  678.         tn = tp - ytick1;
  679.         if (lsy) {
  680.             if (lly) {
  681.             for (i = 7; i >= 0; i--) {
  682.                 temp = tn + xlog[i];
  683.                 if (BETW(temp, vpwymi, vpwyma))
  684.                 plytik(xorigin, plP_wcpcy(temp), i1y, i2y);
  685.             }
  686.             }
  687.             else {
  688.             for (i = nysub1 - 1; i >= 1; i--) {
  689.                 temp = tn + i * (tp - tn) / nysub1;
  690.                 if (BETW(temp, vpwymi, vpwyma))
  691.                 plytik(xorigin, plP_wcpcy(temp), i1y, i2y);
  692.             }
  693.             }
  694.         }
  695.         if (!BETW(tn, vpwymi, vpwyma))
  696.             break;
  697.         plytik(xorigin, plP_wcpcy(tn), i3y, i4y);
  698.         tp = tn;
  699.         }
  700.     }
  701.     plP_draphy(xorigin, vppymi);
  702.     }
  703.  
  704.     /* Draw grid in x direction */
  705.  
  706.     if (lgx) {
  707.     tp = xtick1 * (1. + floor(vpwxmi / xtick1 + .5));
  708.     for (tn = tp; BETW(tn + xtick1 / 2., vpwxmi, vpwxma); tn += xtick1)
  709.         pljoin(tn, vpwymi, tn, vpwyma);
  710.     }
  711.  
  712.     /* Draw grid in y direction */
  713.     if (lgy) {
  714.     tp = ytick1 * (1. + floor(vpwymi / ytick1 + .5));
  715.     for (tn = tp; BETW(tn + ytick1 / 2., vpwymi, vpwyma); tn += ytick1)
  716.         pljoin(vpwxmi, tn, vpwxma, tn);
  717.     }
  718.  
  719.     /* Write horizontal label(s) */
  720.  
  721.     if ((lmx || lnx) && ltx) {
  722.     tp = xtick1 * (1. + floor(vpwxmi / xtick1));
  723.     for (tn = tp; BETW(tn, vpwxmi, vpwxma); tn += xtick1) {
  724.         if (!llx)
  725.         plform(tn, xscale, xprec, string);
  726.         else {
  727.         sprintf(string, "10#u%d", (int) ROUND(tn));
  728.         }
  729.         pos = (tn - vpwxmi) / (vpwxma - vpwxmi);
  730.         if (lnx)
  731.         plmtex("b", 1.5, pos, 0.5, string);
  732.         if (lmx)
  733.         plmtex("t", 1.5, pos, 0.5, string);
  734.     }
  735.     xdigits = 2;
  736.     plsxax(xdigmax, xdigits);
  737.  
  738. /* Write separate exponential label if mode = 1. */
  739.  
  740.     if (!llx && xmode) {
  741.         pos = 1.0;
  742.         height = 3.2;
  743.         sprintf(string, "(x10#u%d#d)", (int) xscale);
  744.         if (lnx)
  745.         plmtex("b", height, pos, 0.5, string);
  746.         if (lmx)
  747.         plmtex("t", height, pos, 0.5, string);
  748.     }
  749.     }
  750.  
  751.     /* Write vertical label(s) */
  752.  
  753.     if ((lmy || lny) && lty) {
  754.     ydigits = 0;
  755.     tp = ytick1 * (1. + floor(vpwymi / ytick1));
  756.     for (tn = tp; BETW(tn, vpwymi, vpwyma); tn += ytick1) {
  757.         if (!lly)
  758.         plform(tn, yscale, yprec, string);
  759.         else
  760.         sprintf(string, "10#u%d", (int) ROUND(tn));
  761.  
  762.         pos = (tn - vpwymi) / (vpwyma - vpwymi);
  763.         if (lny) {
  764.         if (lvy)
  765.             plmtex("lv", 0.5, pos, 1.0, string);
  766.         else
  767.             plmtex("l", 1.5, pos, 0.5, string);
  768.         }
  769.         if (lmy) {
  770.         if (lvy)
  771.             plmtex("rv", 0.5, pos, 0.0, string);
  772.         else
  773.             plmtex("r", 1.5, pos, 0.5, string);
  774.         }
  775.         lstring = strlen(string);
  776.         ydigits = MAX(ydigits, lstring);
  777.     }
  778.     if (!lvy)
  779.         ydigits = 2;
  780.     plsyax(ydigmax, ydigits);
  781.  
  782. /* Write separate exponential label if mode = 1. */
  783.  
  784.     if (!lly && ymode) {
  785.         sprintf(string, "(x10#u%d#d)", (int) yscale);
  786.         offset = 0.02;
  787.         height = 2.0;
  788.         if (lny) {
  789.         pos = 0.0 - offset;
  790.         plmtex("t", height, pos, 1.0, string);
  791.         }
  792.         if (lmy) {
  793.         pos = 1.0 + offset;
  794.         plmtex("t", height, pos, 0.0, string);
  795.         }
  796.     }
  797.     }
  798.     /* Restore the clip limits to viewport edge */
  799.  
  800.     plP_sclp(lxmin, lxmax, lymin, lymax);
  801. }
  802.  
  803. /*----------------------------------------------------------------------*\
  804.  * void plbox3()
  805.  *
  806.  * This is the 3-d analogue of plbox().
  807. \*----------------------------------------------------------------------*/
  808.  
  809. void
  810. c_plbox3(const char *xopt, const char *xlabel, PLFLT xtick, PLINT nsubx,
  811.      const char *yopt, const char *ylabel, PLFLT ytick, PLINT nsuby,
  812.      const char *zopt, const char *zlabel, PLFLT ztick, PLINT nsubz)
  813. {
  814.     PLFLT dx, dy, tx, ty, ux, uy;
  815.     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
  816.     PLFLT cxx, cxy, cyx, cyy, cyz;
  817.     PLINT ln, font;
  818.     PLINT *zbflg, *zbcol;
  819.     PLFLT *zbtck;
  820.     PLINT xdigmax, xdigits;
  821.     PLINT ydigmax, ydigits;
  822.     PLINT zdigmax, zdigits;
  823.  
  824.     if (plsc->level < 3) {
  825.     plabort("plbox3: Please set up window first");
  826.     return;
  827.     }
  828.  
  829.     plP_gw3wc(&cxx, &cxy, &cyx, &cyy, &cyz);
  830.     plP_gdom(&xmin, &xmax, &ymin, &ymax);
  831.     plP_grange(&zscale, &zmin, &zmax);
  832.  
  833.     plgxax(&xdigmax, &xdigits);
  834.     plgyax(&ydigmax, &ydigits);
  835.     plgzax(&zdigmax, &zdigits);
  836.  
  837.     xdigits = xdigmax;
  838.     ydigits = ydigmax;
  839.     zdigits = zdigmax;
  840.  
  841. /* We have to wait until after the plot is drawn to draw back */
  842. /* grid so store this stuff. */
  843.  
  844.     plP_gzback(&zbflg, &zbcol, &zbtck);
  845.     *zbflg = plP_stsearch(zopt, 'd');
  846.     if (*zbflg) {
  847.     /* save tick spacing and color */
  848.     *zbtck = ztick;
  849.     plP_gatt(&font, zbcol);
  850.     }
  851.  
  852.     if (cxx >= 0.0 && cxy <= 0.0) {
  853.     ln = plP_stsearch(xopt, 'n');
  854.     tx = plP_w3wcx(xmin, ymin, zmin);
  855.     ty = plP_w3wcy(xmin, ymin, zmin);
  856.     ux = plP_w3wcx(xmax, ymin, zmin);
  857.     uy = plP_w3wcy(xmax, ymin, zmin);
  858.     plxybx(xopt, xlabel, tx, ty, ux, uy,
  859.            xmin, xmax, xtick, nsubx, 0, &xdigits);
  860.  
  861.     dx = ux - tx;
  862.     dy = uy - ty;
  863.     plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
  864.           plP_w3wcy(xmax, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  865.  
  866.     tx = plP_w3wcx(xmin, ymax, zmin);
  867.     ty = plP_w3wcy(xmin, ymax, zmin);
  868.     ux = plP_w3wcx(xmin, ymin, zmin);
  869.     uy = plP_w3wcy(xmin, ymin, zmin);
  870.     plxybx(yopt, ylabel, tx, ty, ux, uy,
  871.            ymax, ymin, ytick, nsuby, ln, &ydigits);
  872.  
  873.     dx = ux - tx;
  874.     dy = uy - ty;
  875.     plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
  876.           plP_w3wcy(xmin, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  877.     }
  878.     else if (cxx <= 0.0 && cxy <= 0.0) {
  879.     ln = plP_stsearch(yopt, 'n');
  880.     tx = plP_w3wcx(xmin, ymax, zmin);
  881.     ty = plP_w3wcy(xmin, ymax, zmin);
  882.     ux = plP_w3wcx(xmin, ymin, zmin);
  883.     uy = plP_w3wcy(xmin, ymin, zmin);
  884.     plxybx(yopt, ylabel, tx, ty, ux, uy,
  885.            ymax, ymin, ytick, nsuby, 0, &ydigits);
  886.  
  887.     dx = ux - tx;
  888.     dy = uy - ty;
  889.     plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
  890.           plP_w3wcy(xmin, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  891.  
  892.     tx = plP_w3wcx(xmax, ymax, zmin);
  893.     ty = plP_w3wcy(xmax, ymax, zmin);
  894.     ux = plP_w3wcx(xmin, ymax, zmin);
  895.     uy = plP_w3wcy(xmin, ymax, zmin);
  896.     plxybx(xopt, xlabel, tx, ty, ux, uy,
  897.            xmax, xmin, xtick, nsubx, ln, &xdigits);
  898.  
  899.     dx = ux - tx;
  900.     dy = uy - ty;
  901.     plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
  902.           plP_w3wcy(xmax, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  903.     }
  904.     else if (cxx <= 0.0 && cxy >= 0.0) {
  905.     ln = plP_stsearch(xopt, 'n');
  906.     tx = plP_w3wcx(xmax, ymax, zmin);
  907.     ty = plP_w3wcy(xmax, ymax, zmin);
  908.     ux = plP_w3wcx(xmin, ymax, zmin);
  909.     uy = plP_w3wcy(xmin, ymax, zmin);
  910.     plxybx(xopt, xlabel, tx, ty, ux, uy,
  911.            xmax, xmin, xtick, nsubx, 0, &xdigits);
  912.  
  913.     dx = ux - tx;
  914.     dy = uy - ty;
  915.     plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
  916.           plP_w3wcy(xmin, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  917.  
  918.     tx = plP_w3wcx(xmax, ymin, zmin);
  919.     ty = plP_w3wcy(xmax, ymin, zmin);
  920.     ux = plP_w3wcx(xmax, ymax, zmin);
  921.     uy = plP_w3wcy(xmax, ymax, zmin);
  922.     plxybx(yopt, ylabel, tx, ty, ux, uy,
  923.            ymin, ymax, ytick, nsuby, ln, &ydigits);
  924.  
  925.     dx = ux - tx;
  926.     dy = uy - ty;
  927.     plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
  928.           plP_w3wcy(xmax, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  929.     }
  930.     else if (cxx >= 0.0 && cxy >= 0.0) {
  931.     ln = plP_stsearch(yopt, 'n');
  932.     tx = plP_w3wcx(xmax, ymin, zmin);
  933.     ty = plP_w3wcy(xmax, ymin, zmin);
  934.     ux = plP_w3wcx(xmax, ymax, zmin);
  935.     uy = plP_w3wcy(xmax, ymax, zmin);
  936.     plxybx(yopt, ylabel, tx, ty, ux, uy,
  937.            ymin, ymax, ytick, nsuby, 0, &ydigits);
  938.  
  939.     dx = ux - tx;
  940.     dy = uy - ty;
  941.     plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
  942.           plP_w3wcy(xmax, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  943.  
  944.     tx = plP_w3wcx(xmin, ymin, zmin);
  945.     ty = plP_w3wcy(xmin, ymin, zmin);
  946.     ux = plP_w3wcx(xmax, ymin, zmin);
  947.     uy = plP_w3wcy(xmax, ymin, zmin);
  948.     plxybx(xopt, xlabel, tx, ty, ux, uy,
  949.            xmin, xmax, xtick, nsubx, ln, &xdigits);
  950.  
  951.     dx = ux - tx;
  952.     dy = uy - ty;
  953.     plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
  954.           plP_w3wcy(xmin, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
  955.     }
  956.     plsxax(xdigmax, xdigits);
  957.     plsyax(ydigmax, ydigits);
  958.     plszax(zdigmax, zdigits);
  959. }
  960.  
  961. /*----------------------------------------------------------------------*\
  962.  * Support routines for 3d box draw.
  963. \*----------------------------------------------------------------------*/
  964.  
  965. /*----------------------------------------------------------------------*\
  966.  * void plxbyx()
  967.  *
  968.  * This draws a sloping line from (wx1,wy1) to (wx2,wy2) which represents an
  969.  * axis of a 3-d graph with data values from "vmin" to "vmax". Depending on
  970.  * "opt", vertical ticks and/or subticks are placed on the line at major tick
  971.  * interval "tick" with "nsub" subticks between major ticks. If "tick" and/or
  972.  * "nsub" is zero, automatic tick positions are computed
  973.  *
  974.  * B: Draw box boundary
  975.  * I: Inverts tick marks (i.e. drawn downwards)
  976.  * L: Logarithmic axes, major ticks at decades, minor ticks at units
  977.  * N: Write numeric label
  978.  * T: Draw major tick marks
  979.  * S: Draw minor tick marks
  980.  * U: Write label on line
  981. \*----------------------------------------------------------------------*/
  982.  
  983. static void
  984. plxybx(const char *opt, const char *label, PLFLT wx1, PLFLT wy1,
  985.        PLFLT wx2, PLFLT wy2, PLFLT vmin, PLFLT vmax,
  986.        PLFLT tick, PLINT nsub, PLINT nolast, PLINT *digits)
  987. {
  988.     static char string[40];
  989.     PLINT lb, li, ll, ln, ls, lt, lu;
  990.     PLINT major, minor, mode, prec, scale;
  991.     PLINT i, i1, i2, i3, i4;
  992.     PLINT nsub1;
  993.     PLFLT pos, tn, tp, temp, height, tick1;
  994.     PLFLT dwx, dwy, lambda;
  995.  
  996.     dwx = wx2 - wx1;
  997.     dwy = wy2 - wy1;
  998.  
  999.     /* Tick and subtick sizes in device coords */
  1000.  
  1001.     major = MAX(ROUND(plsc->majht * plsc->ypmm), 1);
  1002.     minor = MAX(ROUND(plsc->minht * plsc->ypmm), 1);
  1003.  
  1004.     tick1 = tick;
  1005.     nsub1 = nsub;
  1006.  
  1007.     lb = plP_stsearch(opt, 'b');
  1008.     li = plP_stsearch(opt, 'i');
  1009.     ll = plP_stsearch(opt, 'l');
  1010.     ln = plP_stsearch(opt, 'n');
  1011.     ls = plP_stsearch(opt, 's');
  1012.     lt = plP_stsearch(opt, 't');
  1013.     lu = plP_stsearch(opt, 'u');
  1014.  
  1015.     if (lu)
  1016.     plxytx(wx1, wy1, wx2, wy2, 3.2, 0.5, 0.5, label);
  1017.     if (!lb)
  1018.     return;
  1019.  
  1020.     if (ll)
  1021.     tick1 = 1.0;
  1022.     if (lt)
  1023.     pldtik(vmin, vmax, &tick1, &nsub1, &mode, &prec, *digits, &scale);
  1024.  
  1025.     if (li) {
  1026.     i1 = minor;
  1027.     i2 = 0;
  1028.     i3 = major;
  1029.     i4 = 0;
  1030.     }
  1031.     else {
  1032.     i1 = 0;
  1033.     i2 = minor;
  1034.     i3 = 0;
  1035.     i4 = major;
  1036.     }
  1037.  
  1038.     /* Draw the line */
  1039.  
  1040.     plP_movwor(wx1, wy1);
  1041.     if (lt) {
  1042.     tp = tick1 * floor(vmin / tick1);
  1043.     for (;;) {
  1044.         tn = tp + tick1;
  1045.         if (ls) {
  1046.         if (ll) {
  1047.             for (i = 0; i <= 7; i++) {
  1048.             temp = tp + xlog[i];
  1049.             if (BETW(temp, vmin, vmax)) {
  1050.                 lambda = (temp - vmin) / (vmax - vmin);
  1051.                 plxtik(plP_wcpcx((PLFLT) (wx1 + lambda * dwx)),
  1052.                    plP_wcpcy((PLFLT) (wy1 + lambda * dwy)),
  1053.                    i1, i2);
  1054.             }
  1055.             }
  1056.         }
  1057.         else {
  1058.             for (i = 1; i <= nsub1 - 1; i++) {
  1059.             temp = tp + i * (tn - tp) / nsub1;
  1060.             if (BETW(temp, vmin, vmax)) {
  1061.                 lambda = (temp - vmin) / (vmax - vmin);
  1062.                 plxtik(plP_wcpcx((PLFLT) (wx1 + lambda * dwx)),
  1063.                    plP_wcpcy((PLFLT) (wy1 + lambda * dwy)),
  1064.                    i1, i2);
  1065.             }
  1066.             }
  1067.         }
  1068.         }
  1069.         temp = tn;
  1070.         if (!BETW(temp, vmin, vmax))
  1071.         break;
  1072.  
  1073.         lambda = (temp - vmin) / (vmax - vmin);
  1074.         plxtik(plP_wcpcx((PLFLT) (wx1 + lambda * dwx)),
  1075.            plP_wcpcy((PLFLT) (wy1 + lambda * dwy)), i3, i4);
  1076.         tp = tn;
  1077.     }
  1078.     }
  1079.  
  1080.     plP_drawor(wx2, wy2);
  1081.  
  1082.     /* Label the line */
  1083.  
  1084.     if (ln && lt) {
  1085.     pos = 1.0;
  1086.     height = 3.2;
  1087.     tp = tick1 * (1. + floor(vmin / tick1));
  1088.     for (tn = tp; BETW(tn, vmin, vmax); tn += tick1) {
  1089.         if (nolast && !BETW(tn + tick1, vmin, vmax)) {
  1090.         pos = 0.8;
  1091.         break;
  1092.         }
  1093.         if (!ll)
  1094.         plform(tn, scale, prec, string);
  1095.         else
  1096.         sprintf(string, "10#u%-d", (int) ROUND(tn));
  1097.         pos = (tn - vmin) / (vmax - vmin);
  1098.         plxytx(wx1, wy1, wx2, wy2, 1.5, pos, 0.5, string);
  1099.     }
  1100.     *digits = 2;
  1101.     if (!ll && mode) {
  1102.         sprintf(string, "(x10#u%d#d)", (int) scale);
  1103.         plxytx(wx1, wy1, wx2, wy2, height, pos, 0.5, string);
  1104.     }
  1105.     }
  1106. }
  1107.  
  1108. /*----------------------------------------------------------------------*\
  1109.  * void plxytx()
  1110.  *
  1111.  * Prints out text along a sloping axis joining world coordinates
  1112.  * (wx1,wy1) to (wx2,wy2). Parameters are as for plmtext.
  1113. \*----------------------------------------------------------------------*/
  1114.  
  1115. static void
  1116. plxytx(PLFLT wx1, PLFLT wy1, PLFLT wx2, PLFLT wy2,
  1117.        PLFLT disp, PLFLT pos, PLFLT just, const char *text)
  1118. {
  1119.     PLINT refx, refy;
  1120.     PLFLT shift, cc, ss, def, ht;
  1121.     PLFLT xform[4], diag;
  1122.     PLFLT xscl, xoff, yscl, yoff, wx, wy;
  1123.  
  1124.     plgchr(&def, &ht);
  1125.     plP_gwm(&xscl, &xoff, &yscl, &yoff);
  1126.     cc = xscl * (wx2 - wx1);
  1127.     ss = yscl * (wy2 - wy1);
  1128.     diag = sqrt(cc * cc + ss * ss);
  1129.     cc = cc / diag;
  1130.     ss = ss / diag;
  1131.  
  1132.     xform[0] = cc;
  1133.     xform[1] = 0.0;
  1134.     xform[2] = ss;
  1135.     xform[3] = 1.0;
  1136.  
  1137.     shift = 0.0;
  1138.     if (just != 0.0)
  1139.     shift = plstrl(text) * just;
  1140.     wx = wx1 + pos * (wx2 - wx1);
  1141.     wy = wy1 + pos * (wy2 - wy1);
  1142.  
  1143.     refx = plP_mmpcx((PLFLT) (plP_wcmmx(wx) - shift * cc));
  1144.     refy = plP_mmpcy((PLFLT) (plP_wcmmy(wy) - shift * ss - disp * ht));
  1145.     plstr(0, xform, refx, refy, text);
  1146. }
  1147.  
  1148. /*----------------------------------------------------------------------*\
  1149.  * void plzbx()
  1150.  *
  1151.  * This draws a vertical line from (wx,wy1) to (wx,wy2) which represents the
  1152.  * vertical axis of a 3-d graph with data values from "vmin" to "vmax".
  1153.  * Depending on "opt", ticks and/or subticks are placed on the line at major
  1154.  * tick interval "tick" with "nsub" subticks between major ticks. If "tick"
  1155.  * and/or "nsub" is zero, automatic tick positions are computed
  1156.  *
  1157.  * B: Draws left-hand axis
  1158.  * C: Draws right-hand axis
  1159.  * I: Inverts tick marks (i.e. drawn to the left)
  1160.  * L: Logarithmic axes, major ticks at decades, minor ticks at units
  1161.  * M: Write numeric label on right axis
  1162.  * N: Write numeric label on left axis
  1163.  * S: Draw minor tick marks
  1164.  * T: Draw major tick marks
  1165.  * U: Writes left-hand label
  1166.  * V: Writes right-hand label
  1167. \*----------------------------------------------------------------------*/
  1168.  
  1169. static void
  1170. plzbx(const char *opt, const char *label, PLINT right, PLFLT dx, PLFLT dy,
  1171.       PLFLT wx, PLFLT wy1, PLFLT wy2, PLFLT vmin, PLFLT vmax,
  1172.       PLFLT tick, PLINT nsub, PLINT *digits)
  1173. {
  1174.     static char string[40];
  1175.     PLINT lb, lc, li, ll, lm, ln, ls, lt, lu, lv;
  1176.     PLINT i, mode, prec, scale;
  1177.     PLINT nsub1, lstring;
  1178.     PLFLT pos, tn, tp, temp, height, tick1;
  1179.     PLFLT dwy, lambda, diag, major, minor, xmajor, xminor;
  1180.     PLFLT ymajor, yminor, dxm, dym, xscl, xoff, yscl, yoff;
  1181.  
  1182.     dwy = wy2 - wy1;
  1183.  
  1184.     /* Tick and subtick sizes in device coords */
  1185.  
  1186.     major = plsc->majht;
  1187.     minor = plsc->minht;
  1188.  
  1189.     tick1 = tick;
  1190.     nsub1 = nsub;
  1191.  
  1192.     lb = plP_stsearch(opt, 'b');
  1193.     lc = plP_stsearch(opt, 'c');
  1194.     li = plP_stsearch(opt, 'i');
  1195.     ll = plP_stsearch(opt, 'l');
  1196.     lm = plP_stsearch(opt, 'm');
  1197.     ln = plP_stsearch(opt, 'n');
  1198.     ls = plP_stsearch(opt, 's');
  1199.     lt = plP_stsearch(opt, 't');
  1200.     lu = plP_stsearch(opt, 'u');
  1201.     lv = plP_stsearch(opt, 'v');
  1202.  
  1203.     if (lu && !right)
  1204.     plztx("h", dx, dy, wx, wy1, wy2, 5.0, 0.5, 0.5, label);
  1205.  
  1206.     if (lv && right)
  1207.     plztx("h", dx, dy, wx, wy1, wy2, -5.0, 0.5, 0.5, label);
  1208.  
  1209.     if (right && !lc)
  1210.     return;
  1211.  
  1212.     if (!right && !lb)
  1213.     return;
  1214.  
  1215.     if (ll)
  1216.     tick1 = 1.0;
  1217.  
  1218.     if (lt)
  1219.     pldtik(vmin, vmax, &tick1, &nsub1, &mode, &prec, *digits, &scale);
  1220.  
  1221.     if ((li && !right) || (!li && right)) {
  1222.     minor = -minor;
  1223.     major = -major;
  1224.     }
  1225.  
  1226.     plP_gwm(&xscl, &xoff, &yscl, &yoff);
  1227.     dxm = dx * xscl;
  1228.     dym = dy * yscl;
  1229.     diag = sqrt(dxm * dxm + dym * dym);
  1230.  
  1231.     xminor = minor * dxm / diag;
  1232.     xmajor = major * dxm / diag;
  1233.     yminor = minor * dym / diag;
  1234.     ymajor = major * dym / diag;
  1235.  
  1236.     /* Draw the line */
  1237.  
  1238.     plP_movwor(wx, wy1);
  1239.     if (lt) {
  1240.     tp = tick1 * floor(vmin / tick1);
  1241.     for (;;) {
  1242.         tn = tp + tick1;
  1243.         if (ls) {
  1244.         if (ll) {
  1245.             for (i = 0; i <= 7; i++) {
  1246.             temp = tp + xlog[i];
  1247.             if (BETW(temp, vmin, vmax)) {
  1248.                 lambda = (temp - vmin) / (vmax - vmin);
  1249.                 plstik(plP_wcmmx(wx),
  1250.                    plP_wcmmy((PLFLT) (wy1 + lambda * dwy)),
  1251.                    xminor, yminor);
  1252.             }
  1253.             }
  1254.         }
  1255.         else {
  1256.             for (i = 1; i <= nsub1 - 1; i++) {
  1257.             temp = tp + i * tick1 / nsub1;
  1258.             if (BETW(temp, vmin, vmax)) {
  1259.                 lambda = (temp - vmin) / (vmax - vmin);
  1260.                 plstik(plP_wcmmx(wx),
  1261.                    plP_wcmmy((PLFLT) (wy1 + lambda * dwy)),
  1262.                    xminor, yminor);
  1263.             }
  1264.             }
  1265.         }
  1266.         }
  1267.         temp = tn;
  1268.         if (!BETW(temp, vmin, vmax))
  1269.         break;
  1270.         lambda = (temp - vmin) / (vmax - vmin);
  1271.         plstik(plP_wcmmx(wx), plP_wcmmy((PLFLT) (wy1 + lambda * dwy)),
  1272.            xmajor, ymajor);
  1273.         tp = tn;
  1274.     }
  1275.     }
  1276.  
  1277.     plP_drawor(wx, wy2);
  1278.  
  1279.     /* Label the line */
  1280.  
  1281.     if ((ln || lm) && lt) {
  1282.     *digits = 0;
  1283.     tp = tick1 * floor(vmin / tick1);
  1284.     for (tn = tp + tick1; BETW(tn, vmin, vmax); tn += tick1) {
  1285.         if (!ll)
  1286.         plform(tn, scale, prec, string);
  1287.         else
  1288.         sprintf(string, "10#u%d", (int) ROUND(tn));
  1289.         pos = (tn - vmin) / (vmax - vmin);
  1290.         if (ln && !right)
  1291.         plztx("v", dx, dy, wx, wy1, wy2, 0.5, pos, 1.0, string);
  1292.  
  1293.         if (lm && right)
  1294.         plztx("v", dx, dy, wx, wy1, wy2, -0.5, pos, 0.0, string);
  1295.  
  1296.         lstring = strlen(string);
  1297.         *digits = MAX(*digits, lstring);
  1298.     }
  1299.     if (!ll && mode) {
  1300.         sprintf(string, "(x10#u%d#d)", (int) scale);
  1301.         pos = 1.15;
  1302.         height = 0.5;
  1303.         if (ln && !right) {
  1304.         plztx("v", dx, dy, wx, wy1, wy2, height, pos, 1.0, string);
  1305.         }
  1306.         if (lm && right) {
  1307.         plztx("v", dx, dy, wx, wy1, wy2,
  1308.               (PLFLT) -height, pos, 0.0, string);
  1309.         }
  1310.     }
  1311.     }
  1312. }
  1313.  
  1314. /*----------------------------------------------------------------------*\
  1315.  * void plztx()
  1316.  *
  1317.  * Prints out text along a vertical axis for a 3d plot joining
  1318.  * world coordinates (wx,wy1) to (wx,wy2).
  1319. \*----------------------------------------------------------------------*/
  1320.  
  1321. static void
  1322. plztx(const char *opt, PLFLT dx, PLFLT dy, PLFLT wx, PLFLT wy1,
  1323.       PLFLT wy2, PLFLT disp, PLFLT pos, PLFLT just, const char *text)
  1324. {
  1325.     PLINT refx = 0, refy = 0;
  1326.     PLINT vert = 0;
  1327.     PLFLT shift, cc, ss, def, ht;
  1328.     PLFLT xform[4], diag;
  1329.     PLFLT xscl, xoff, yscl, yoff, wy;
  1330.  
  1331.     plgchr(&def, &ht);
  1332.     plP_gwm(&xscl, &xoff, &yscl, &yoff);
  1333.     cc = xscl * dx;
  1334.     ss = yscl * dy;
  1335.     diag = sqrt(cc * cc + ss * ss);
  1336.     cc = cc / diag;
  1337.     ss = ss / diag;
  1338.     plP_gmp(&xscl, &xoff, &yscl, &yoff);
  1339.  
  1340.     shift = 0.0;
  1341.     if (just != 0.0)
  1342.     shift = plstrl(text) * just;
  1343.     wy = wy1 + pos * (wy2 - wy1);
  1344.  
  1345.     if (plP_stsearch(opt, 'v')) {
  1346.     vert = 0;
  1347.     refx = plP_mmpcx((PLFLT) (plP_wcmmx(wx) - (disp * ht + shift) * cc));
  1348.     refy = plP_mmpcy((PLFLT) (plP_wcmmy(wy) - (disp * ht + shift) * ss));
  1349.     }
  1350.     else if (plP_stsearch(opt, 'h')) {
  1351.     vert = 1;
  1352.     refy = plP_wcpcy(wy) - yscl * (disp * ht * ss + shift);
  1353.     refx = plP_mmpcx((PLFLT) (plP_wcmmx(wx) - disp * ht * cc));
  1354.     }
  1355.     if (vert) {
  1356.     xform[0] = 0.0;
  1357.     xform[1] = -cc;
  1358.     xform[2] = 1.0;
  1359.     xform[3] = -ss;
  1360.     }
  1361.     else {
  1362.     xform[0] = cc;
  1363.     xform[1] = 0.0;
  1364.     xform[2] = ss;
  1365.     xform[3] = 1.0;
  1366.     }
  1367.     plstr(0, xform, refx, refy, text);
  1368. }
  1369.  
  1370. /*----------------------------------------------------------------------*\
  1371.  * void plform()
  1372.  *
  1373.  * Formats a floating point value in one of the following formats 
  1374.  * (i)    If scale == 0, use floating point format with "prec" places
  1375.  *    after the decimal point. 
  1376.  * (ii)    If scale == 1, use scientific notation with one place before 
  1377.  *    the decimal point and "prec" places after.  In this case, the
  1378.  *    value must be divided by 10^scale.
  1379. \*----------------------------------------------------------------------*/
  1380.  
  1381. static void
  1382. plform(PLFLT value, PLINT scale, PLINT prec, char *result)
  1383. {
  1384.     PLINT setpre, precis;
  1385.     char form[10], temp[30];
  1386.     double scale2;
  1387.  
  1388.     plP_gprec(&setpre, &precis);
  1389.  
  1390.     if(setpre)
  1391.     prec = precis;
  1392.  
  1393.     if(scale)
  1394.     value /= pow(10.,(double)scale);
  1395.  
  1396. /* This is necessary to prevent labels like "-0.0" on some systems */
  1397.  
  1398.     scale2 = pow(10., prec);
  1399.     value = floor((value * scale2) + .5) / scale2;
  1400.  
  1401.     sprintf(form, "%%.%df", (int) prec);
  1402.     sprintf(temp, form, value);
  1403.     strcpy(result, temp);
  1404. }
  1405.  
  1406.